home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / apps / 112 / ccheck / ccheck.c next >
C/C++ Source or Header  |  1987-11-27  |  17KB  |  831 lines

  1. #define UNIX 1     /*  Define for UNIX environment  */
  2. /*
  3.  * CCHECK.C -- Translated to Mark Williams C on the Atari ST 1/20/87
  4.  *
  5.  *    Copyright:    The Regents of the University of California
  6.  *            [Note - since Steve Draper distributed cchk.c over
  7.  *             Usenet, I assume it's effectively in the public
  8.  *             domain. JCM]
  9.  *            
  10.  *    Title:        ccheck
  11.  *
  12.  *    Purpose:    To find and report all badly matched openers and
  13.  *            closers plus assignment/equality confusions
  14.  *            in a c source file.
  15.  *
  16.  *    Author:        Steve Draper, expanding cnest by Tom Anderson
  17.  *
  18.  *    Usage:        ccheck [-q] [-v] <filename1> <filename2> ...
  19.  *
  20.  *             January 20, 1987        Rewritten for the ATARI ST
  21.  *                        Computers by Matt Leber
  22.  *                
  23.  *                Changed source so that it would print an error
  24.  *                 message when no parameters were specified.
  25.  */
  26.  
  27. #ifdef UNIX
  28. #include <stdio.h>
  29. #include <ctype.h>
  30. #else
  31. #include <a:bdscio.h>
  32. #include <a:dio.h>
  33. #endif
  34.  
  35. #define TRUE 1
  36. #define FALSE 0
  37. #define SPACE 32
  38.  
  39. #define BRACE    1
  40. #define SQBRAK     2
  41. #define PAREN    3
  42. #define IF    4
  43. #define IFCOND    5
  44. #define WHLCOND    6
  45. #define THEN    7
  46. #define ELSE    8
  47.  
  48. #define STACKSIZ 40
  49.  
  50. struct brak 
  51. {
  52.     int type, b_indent, b_ln;
  53. }
  54. stack[STACKSIZ];
  55.  
  56. #define rmbrak(N) (top -= N, stackc -= N)
  57. #define myungetc(C)  ungetc(((C) == '\n' ? SPACE : (C)), infile)
  58.  
  59. #ifndef UNIX
  60. /*
  61.  * Kludge defines for BDS C
  62.  */
  63. #define void int
  64. #define stdin 0
  65. #define stdout 1
  66. #define VFLAG "-V"
  67. #define QFLAG "-Q"
  68. #define SFLAG "-S"
  69. int eofdet;
  70. #else
  71. #define VFLAG "-v"
  72. #define QFLAG "-q"
  73. #define SFLAG "-s"
  74. #endif
  75.  
  76. int firsttime; /* This was a static in mygetchar() */
  77.  
  78. int mygetchar(), pr();
  79. void checkelse(), newbrak(), checkcloser(), prtype();
  80.  
  81. #ifndef UNIX
  82. FILE fbuff;
  83. #endif
  84.  
  85. FILE *infile;
  86. int ln, indent, commindent, stackc, commln;
  87. int singlequoterr, oddsinglequote, bracecnt, parencnt, sqbrakcnt;
  88. int errstatus, wstatus;
  89. int errnmb, wnmb;
  90. int verbose;
  91. char *filename;
  92. struct brak *top;
  93.  
  94. main(argc,argv)
  95. unsigned argc ;
  96. char *argv[] ;
  97. {
  98.     register int c ;
  99.     int i;
  100.     int doubleqflag;
  101.     unsigned file_index;
  102.  
  103. #ifndef UNIX
  104.     dioinit(&argc, argv); /* Initialize redirection for BDS C */
  105.     argv[0] = "ccheck"; /* Sigh... */
  106.     infile = fbuff;
  107. #endif
  108.     wnmb = 0;
  109.     verbose = 0;
  110.     file_index = 1;
  111.     
  112.     puts("\nCcheck - C source code checker");
  113.     puts("Ported to the Atari ST by Matt Leber\n"); 
  114.     while (argc > 1  &&  argv[file_index][0] == '-') {
  115.     if (strcmp(argv[file_index], VFLAG) == 0)
  116.         verbose++;
  117.     if (strcmp(argv[file_index], QFLAG) == 0)
  118.         wnmb = -2;
  119.     if (strcmp(argv[file_index], SFLAG) == 0)
  120.         wnmb = -2;
  121.     file_index++;
  122.     argc--;
  123.     }
  124.  
  125.     do {
  126.     /* INIT for each file */
  127.     firsttime = 1;
  128.     doubleqflag = 0;
  129.     errstatus = wstatus = 0;
  130.     ln = 1;
  131.     indent = 0;
  132.     commindent = 0;
  133.     singlequoterr = oddsinglequote = parencnt = sqbrakcnt = bracecnt = 0;
  134.     errnmb = 0;
  135.     if (wnmb > -2)
  136.         wnmb = 0;
  137.     newbrak(0);
  138. #ifndef UNIX
  139.     eofdet = 0;
  140. #endif
  141.  
  142.     if (argc == 1) {
  143.         puts("\nUsage : ccheck [-q] [-v] <filename1> <filename2> ...");
  144.             puts("\n-q  :  Quiet mode.  Suppresses warning type messages");
  145.             puts("-v  :  Verbose mode.  Gives more detailed error messages");
  146.             exit(0); 
  147.     }
  148.     else {
  149. #ifdef UNIX
  150.         if ((infile = fopen(argv[file_index],"r")) == (FILE *) NULL)
  151. #else
  152.         if (fopen(argv[file_index], infile) == ERROR)
  153. #endif
  154.         {
  155.         fprintf (stdout,"%s: Can't access %s\n",argv[0], argv[file_index]);
  156.         continue;
  157.         }
  158.         filename = argv[file_index];
  159.     }
  160.  
  161.     while ( ( c = mygetchar()) !=  EOF ) {
  162.         if (verbose == 2) {
  163.         for (i = stackc; i>0; i--) {
  164.             printf("%c %d: type ", c, i);
  165.             prtype(stack[i].type);
  166.             printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i].b_ln);
  167.         }
  168.         }
  169.  
  170.         switch (c) {
  171.         case ';':
  172.         ungetc(SPACE, infile);
  173.         while (top->type == ELSE)
  174.             rmbrak(1);
  175.         if (top->type == THEN) {
  176.             rmbrak(1);
  177.             checkelse();
  178.         }
  179.         break;
  180.  
  181.         case '!':
  182.         case '>':
  183.         case '<':
  184.         /* swallow legit. '=' chars */
  185.         c = mygetchar();
  186.         if (c != '=')
  187.             myungetc(c);
  188.         break;
  189.  
  190.         case '=':
  191.         if ((top-1)->type == IFCOND  ||  (top-1)->type == WHLCOND) {
  192.             c = mygetchar();
  193.             if (c != '=') {
  194.             myungetc(c);
  195.             if (pr(1))
  196.                 printf("Assignment instead of equals in conditional, line %d.\n", ln);
  197.             }
  198.         }
  199.         break;
  200.  
  201.         case '\n':
  202.         case SPACE:
  203.         c = mygetchar();
  204.         switch (c) {
  205.         case 'i':
  206.             /* if */
  207.             c = mygetchar();
  208.             if (c == 'f'
  209.             && !isalpha(c = fgetc(infile)) && !isdigit(c)) {
  210.             ungetc(c, infile);
  211.             newbrak(IF);
  212.             while ((c = mygetchar()) == SPACE ||  c == '\n')
  213.                 ;
  214.             if (c != '(') {
  215.                 if (pr(1))
  216.                 printf("Bad if (no condition) line %d.\n", ln);
  217.                 rmbrak(1);
  218.             }
  219.             else
  220.                 newbrak(IFCOND);
  221.             myungetc(c);
  222.             }
  223.             else
  224.             myungetc(c);
  225.             break;
  226.         case 'w':
  227.             /* while */
  228.             if ((c = mygetchar()) == 'h'
  229.             &&  (c = mygetchar()) == 'i'
  230.             &&  (c = mygetchar()) == 'l'
  231.             &&  (c = mygetchar()) == 'e'
  232.             &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c)) {
  233.             ungetc(c, infile);
  234.             while ((c = mygetchar()) == SPACE ||  c == '\n')
  235.                 ;
  236.             if (c != '(') {
  237.                 if (pr(1))
  238.                 printf("Bad while (no condition) line %d.\n", ln);
  239.             }
  240.             else
  241.                 newbrak(WHLCOND);
  242.             myungetc(c);
  243.             }
  244.             else
  245.             myungetc(c);
  246.             break;
  247.         case 'e':
  248.             /* else */
  249.             myungetc(c);
  250.             checkelse();
  251.             break;
  252.  
  253.         default:
  254.             myungetc(c);
  255.             break;
  256.         }
  257.         break;
  258.  
  259.         case '*':
  260.         /* close comment ? */
  261.         c = mygetchar();
  262.         if (c != '/') {
  263.             myungetc(c);
  264.             break;
  265.         }
  266.  
  267.         if (pr(1))
  268.             printf
  269.             ("Line %d: Comment close without open, indent %d\n",
  270.             ln, indent);
  271.  
  272.         break;
  273.  
  274.  
  275.         case '\'':
  276.         if ((c = fgetc(infile)) != '\\') {
  277.             if (c == '\''  ||  (c = fgetc(infile)) != '\'') {
  278.             if (pr(1))
  279.                 printf("Bad character constant line %d\n", ln);
  280.             singlequoterr = 1;
  281.             }
  282.         }
  283.         else if (!isdigit(c = fgetc(infile))) {
  284.             if ((c = fgetc(infile)) != '\'') {
  285.             if (pr(1))
  286.                 printf("Bad character constant with \\ line %d\n", ln);
  287.             }
  288.         }
  289.         else {
  290.             if (isdigit(c = fgetc(infile)))
  291.             if (isdigit(c = fgetc(infile)))
  292.                 c = fgetc(infile);
  293.             if (c != '\'')
  294.             if (pr(1))
  295.                 printf("Bad character constant with \\0 line %d\n", ln);
  296.         }
  297.  
  298.         if (c != '\'') {
  299.             ungetc(c, infile);
  300.             oddsinglequote = !oddsinglequote;
  301.             singlequoterr = 1;
  302.         }
  303.         break;
  304.  
  305.         case '"':
  306.         do {
  307.             c = fgetc(infile);
  308.             if (c == EOF) {
  309.             if (pr(2))
  310.                 printf("Error: '\"' quoted string not ended by end of file.\n");
  311.             break;
  312.             }
  313.             else if (c == '\n') {
  314.             if (doubleqflag == 0)
  315.                 if (pr(0))
  316.                 printf("Warning: '\"' quoted string not ended by end of line %d.\n", ln);
  317.             doubleqflag = 1;
  318.             ln++;
  319.             }
  320.             else if (c == '\\') {
  321.             c = SPACE;
  322.             fgetc(infile);
  323.             }
  324.         } while (c != '"');
  325.         doubleqflag = 0;
  326.         break;
  327.      
  328.         case '{':
  329.         if (stackc  &&  indent < top->b_indent)
  330.             if (pr(0))
  331.             printf("Indent jumps backwards line %d.\n", ln);
  332.         newbrak(BRACE);
  333.         break;
  334.  
  335.         case '}':
  336.         checkcloser(BRACE);
  337.         while (top->type == ELSE)
  338.             rmbrak(1);
  339.         if (top->type == THEN) {
  340.             rmbrak(1);
  341.             checkelse();
  342.         }
  343.         break;
  344.  
  345.         case '(':
  346.         if (stackc  &&  indent < top->b_indent)
  347.             if (pr(0))
  348.             printf("Indent jumps backwards line %d.\n", ln);
  349.         newbrak(PAREN);
  350.         break;
  351.  
  352.         case ')':
  353.         checkcloser(PAREN);
  354.         if (top->type == IFCOND) {
  355.             rmbrak(1);
  356.             newbrak(THEN);
  357.         }
  358.         else if (top->type == WHLCOND)
  359.             rmbrak(1);
  360.         break;
  361.  
  362.         case '[':
  363.         if (stackc  &&   indent < top->b_indent)
  364.             if (pr(0))
  365.             printf("Indent jumps backwards line %d.\n", ln);
  366.         newbrak(SQBRAK);
  367.         break;
  368.  
  369.         case ']':
  370.         checkcloser(SQBRAK);
  371.         break;
  372.  
  373.         default:
  374.         break;
  375.  
  376.         }
  377.     }
  378.  
  379.     fclose(infile);
  380.  
  381.     while (stackc > 0) {
  382.         pr(2);
  383.         fputs("Unclosed brak at EOF: ", stdout);
  384.         prtype(top->type);
  385.         printf(" opened on line %d.\n", top->b_ln);
  386.         switch (top->type) {
  387.         case BRACE:
  388.             bracecnt++;
  389.             break;
  390.         case SQBRAK:
  391.             sqbrakcnt++;
  392.             break;
  393.         case PAREN:
  394.             parencnt++;
  395.             break;
  396.         default:
  397.             break;
  398.         }
  399.         rmbrak(1);
  400.     }
  401.  
  402.     if ((i = (oddsinglequote || bracecnt || sqbrakcnt || parencnt)) || errstatus) {
  403.         pr(2);
  404.         printf("Summary:\n");
  405.     }
  406.     else {
  407.         if (filename != NULL) {
  408.         fputs(filename, stdout);
  409.         fputs(": ", stdout);
  410.         }
  411.         printf(" OK\n");
  412.     }
  413.     if (oddsinglequote) 
  414.         printf("\tOdd number of single quotes.\n");
  415.     if (bracecnt)
  416.         printf("\t%d too few %s braces.\n", abs(bracecnt), (bracecnt>0 ? "closing" : "opening"));
  417.     if (sqbrakcnt)
  418.         printf("\t%d too few %s square brackets.\n", abs(sqbrakcnt), (sqbrakcnt>0 ? "closing" : "opening"));
  419.     if (parencnt)
  420.         printf("\t%d too few %s parentheses.\n", abs(parencnt), (parencnt>0 ? "closing" : "opening"));
  421.     if (errstatus && !i)
  422.         printf("\tPossible error(s), but no net delimiter imbalance.\n");
  423.     putchar('\n');
  424.     } while (++file_index < argc);
  425.  
  426. #ifndef UNIX
  427.     dioflush(); /* Clean up BDS C redirection */
  428. #endif
  429.     exit(errstatus ? 2 : wstatus);
  430. }
  431.  
  432. /*
  433.  *
  434.  */
  435. int mygetchar()
  436. {
  437.     register int c;
  438.  
  439.     c = fgetc(infile);
  440.  
  441.     /*
  442.     if (c == ';') {
  443.     ungetc(SPACE, infile);
  444.     return(';');
  445.     }
  446.     */
  447.     if (c == '/') {             /* open comment ? */
  448.     c = fgetc(infile);
  449.     if (c != '*') {
  450.         ungetc(c, infile);
  451.         return('/');
  452.     }
  453.     commln = ln;
  454.     commindent = indent;
  455.  
  456.     while (1) {
  457.         c = fgetc(infile);
  458.  
  459.         if (c == EOF) {         /* last comment never ended */
  460.         if (pr(2))
  461.             printf
  462.             ("Comment opened line %d unclosed by end of file.\n",
  463.             commln);
  464.         break; /* Get out of this loop! */
  465.         }
  466.  
  467.         else if (c == '/') {        /* nested comment ? */
  468.         if ((c = fgetc(infile)) == '*') {
  469.             if (pr(0))
  470.             fprintf(stdout,
  471.             "Nested comment: line %d, indent %d.  First open: line %d, indent %d\n",
  472.             ln, indent, commln, commindent);
  473.         }
  474.         else
  475.             ungetc(c, infile);
  476.         }
  477.         else if (c == '*') {        /* end comment ? */
  478.         if ((c = fgetc(infile)) == '/') {
  479.             if (indent != commindent  &&  indent-1 != commindent)
  480.             if (pr(0))
  481.                 printf(
  482.                 "Indent of comment close doesn't match open: lines %d, %d, indents %d, %d\n",
  483.                 commln, ln, commindent, indent);
  484.  
  485.             break;       /* only exit from loop, except EOF */
  486.         }
  487.         else
  488.             ungetc(c, infile);
  489.         }
  490.         else if (c == '\n') {
  491.         do {
  492.             if (c == SPACE)
  493.             indent++;
  494.             else if (c == '\t')
  495.             indent = ((indent+8)/8)*8;
  496.             else if (c == '\n') { 
  497.             ln++;
  498.             indent = 0;
  499.             } 
  500.         } while (isspace(c = fgetc(infile)));
  501.         ungetc(c, infile);
  502.         }
  503.     }
  504.     return(SPACE);
  505.  
  506.     }
  507.  
  508.     if (c == '\n'  ||  firsttime == 1) {
  509.     firsttime = 0;
  510. lf:
  511.     while (1) {
  512.         if (c == SPACE)
  513.         indent++;
  514.         else if (c == '\t')
  515.         indent = ((indent+8)/8)*8;
  516.         else if (c == '\n') { 
  517.         ln++;
  518.         indent = 0;
  519.         singlequoterr = 0;
  520.         } 
  521.         else {
  522.         ungetc(c, infile);
  523.         return('\n');
  524.         /*NOTREACHED*/
  525.         break;
  526.         }
  527.         c = fgetc(infile);
  528.     }
  529.     }
  530.  
  531.     if (c == SPACE  ||  c == '\t') {
  532.     do
  533.         c = fgetc(infile);
  534.     while (c == SPACE  ||  c == '\t');
  535.     if (c != '\n') {
  536.         ungetc(c, infile);
  537.         return(SPACE);
  538.     }
  539.     else
  540.         goto lf;
  541.     }
  542.     return(c);
  543. }
  544.  
  545. /*
  546.  *    administer count of error msgs. and suppress if too many
  547.  *    administer the status var.s
  548.  *    prepend file name to msg.
  549.  *    flag error msg.s (not warnings) with '*'
  550.  */
  551. int pr(error)
  552. int error;
  553. {
  554.     int i;
  555.     
  556.     if (singlequoterr)
  557.     return(0);
  558.  
  559.     if (verbose) {
  560.     for (i = stackc; i>0; i--) {
  561.         printf("%d: type ", i);
  562.         prtype(stack[i].type);
  563.         printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i].b_ln);
  564.     }
  565.     }
  566.  
  567.     if (error == 2) {
  568.     errnmb = 0;
  569.     errstatus = 1;
  570.     }
  571.     else if (error) {
  572.     errstatus = 1;
  573.     if (errnmb < 0)
  574.         return(0);
  575.     else if (errnmb >= 9) {
  576.         errnmb = -1;
  577.         printf("Other error messages being suppressed.\n");
  578.         return(0);
  579.     }
  580.     }
  581.     else {
  582.     wstatus = 1;
  583.     if (wnmb < 0)
  584.         return(0);
  585.     else if (errnmb + wnmb >= 9) {
  586.         wnmb = -1;
  587.         puts("Further warning messages being suppressed.\n");
  588.         return(0);
  589.     }
  590.     }
  591.  
  592.     if (filename != NULL) {
  593.     fputs(filename, stdout);
  594.     fputs(": ", stdout);
  595.     }
  596.     if (error)
  597.     putchar('*');
  598.     if (error)
  599.     errnmb++;
  600.     else
  601.     wnmb++;
  602.     return(1);
  603. }
  604.  
  605. #ifndef UNIX
  606. /*
  607.  * Special fgetc() for BDS C
  608.  *
  609.  * It turns out that, using DIO, getc() is "cooked" (eats CRs, looks for
  610.  * ^z) if input is from redirected stdin, and "raw" if input is from
  611.  * an explicitly opened file.  This fgetc() manages to look the same
  612.  * in either case.
  613.  */
  614. int fgetc(iobuf)
  615. FILE *iobuf;
  616. {
  617.     int c;
  618.  
  619.     if (eofdet)
  620.     return (EOF);
  621.     while ((c = getc(iobuf)) == '\r')
  622.     ;
  623.     if (c == EOF || c == CPMEOF) {
  624.     c = EOF;
  625.     eofdet++;
  626.     }
  627.     return (c);
  628. }
  629. #endif
  630.  
  631. /*
  632.  *
  633.  */
  634. void newbrak(newtype)
  635. int newtype;
  636. {
  637.     if (newtype == 0) {
  638.     top = stack;
  639.     stackc = 0;
  640.     }
  641.     else {
  642.     top++;
  643.     stackc++;
  644.     }
  645.     if (stackc >= STACKSIZ) {
  646.     if (pr(2))
  647.         printf("***stack overflow, line %d.\n", ln);
  648.     exit(3);
  649.     }
  650.  
  651.     top->type = newtype;
  652.     top->b_indent = indent;
  653.     top->b_ln = ln;
  654.  
  655. }
  656.  
  657. /*
  658.  *
  659.  */
  660. void prtype(typ)
  661. int typ;
  662. {
  663.     switch(typ) {
  664.     case BRACE:
  665.     putchar('}');
  666.     break;
  667.     case PAREN:
  668.     putchar(')');
  669.     break;
  670.     case SQBRAK:
  671.     putchar(']');
  672.     break;
  673.     case IF:
  674.     fputs("if", stdout);
  675.     break;
  676.     case IFCOND:
  677.     fputs("if-condition", stdout);
  678.     break;
  679.     case THEN:
  680.     fputs("then", stdout);
  681.     break;
  682.     case ELSE:
  683.     fputs("else", stdout);
  684.     break;
  685.     case WHLCOND:
  686.     fputs("while-condition", stdout);
  687.     break;
  688.     default:
  689.     fputs("'NULL'", stdout);
  690.     break;
  691.     }
  692. }
  693.  
  694. /*
  695.  *
  696.  */
  697. void checkcloser(typ)
  698. int (typ);
  699. {
  700.     int i, found;
  701.  
  702.     i = found = 0;
  703.     if (typ == top->type  &&  top->b_indent == indent) {
  704.     rmbrak(1);
  705.     return;
  706.     }
  707.  
  708.     while (!found  &&  ++i < stackc  &&  indent <= (top-i)->b_indent)
  709.     if (typ == (top-i)->type  &&  (top-i)->b_indent == indent)
  710.         found = 1;
  711.  
  712.     if (found) {
  713.     if (pr(1))
  714.         printf("Missing closer%s detected line %d:\n", (i>1?"s":""), ln);
  715.     while (i--) {
  716.         if (pr(1)) {
  717.         fputs("\tMissing closing ", stdout);
  718.         prtype(top->type);
  719.         printf(" opened line %d.\n", top->b_ln);
  720.         }
  721.         switch (top->type) {
  722.         case BRACE:
  723.             bracecnt++;
  724.             break;
  725.         case SQBRAK:
  726.             sqbrakcnt++;
  727.             break;
  728.         case PAREN:
  729.             parencnt++;
  730.             break;
  731.         default:
  732.         break;
  733.         }
  734.         rmbrak(1);
  735.     }
  736.     rmbrak(1);    /* the matching brak */
  737.     }
  738.     else if (typ == top->type) {
  739.     if (indent != top->b_indent) {
  740.         if (pr(0)) {
  741.         fputs("Mismatched indent on closing ", stdout);
  742.         prtype(typ);
  743.         printf
  744.         (" lines %d, %d; indents %d, %d.\n",
  745.          top->b_ln, ln, top->b_indent, indent);
  746.         }
  747.     }
  748.     rmbrak(1);
  749.     }
  750.  
  751.     else {
  752.     switch (typ) {
  753.     case BRACE:
  754.         bracecnt--;
  755.         break;
  756.     case SQBRAK:
  757.         sqbrakcnt--;
  758.         break;
  759.     case PAREN:
  760.         parencnt--;
  761.         break;
  762.     default:
  763.         break;
  764.     }
  765.  
  766.     if (pr(1)) {
  767.         fputs("Muddle detected at unmatched closing ", stdout);
  768.         prtype(typ);
  769.         printf(" line %d.\n", ln);
  770.     }
  771.     }
  772. }
  773.  
  774. /*
  775.  *    removes IF from stack
  776.  *    checks else's indent
  777.  */
  778. void checkelse()
  779. {
  780.     int c;
  781.  
  782.     while ((c = mygetchar()) == SPACE  || c == '\n')
  783.     ;
  784.     if (c == 'e'
  785.     &&  (c = mygetchar()) == 'l'
  786.     &&  (c = mygetchar()) == 's'
  787.     &&  (c = mygetchar()) == 'e'
  788.     &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c)) {
  789.     ungetc(c, infile);
  790.     if (top->type == THEN)
  791.         rmbrak(1);
  792.     if (top->type != IF) {
  793.         if (pr(1))
  794.         printf("Else with no if line %d.\n", ln);
  795.     }
  796.  
  797.     else if (indent+2 < top->b_indent) {
  798.         if (pr(1))
  799.         printf("Dangling else -- bound to wrong if?  \"if\" line %d, \"else\" line %d.\n", top->b_ln, ln);
  800.     }
  801.  
  802.     else if (indent != top->b_indent) {
  803.         if (pr(0)) {
  804.         fputs("Wrong indent for else", stdout);
  805.         if (indent-2 >  top->b_indent)
  806.             fputs(" (missing if?)", stdout);
  807.         printf(".  \"if\" line %d, \"else\" line %d.\n", top->b_ln, ln);
  808.         }
  809.     }
  810.  
  811.     if (top->type == IF)
  812.         rmbrak(1);
  813.     newbrak(ELSE);
  814.     }
  815.  
  816.     else {
  817.     myungetc(c);
  818.     ungetc(SPACE, infile);  /* BUG?? */
  819.     /* no else so terminate the IF */
  820.     if (top->type == IF) {
  821.         rmbrak(1);
  822.         while (top->type == ELSE)
  823.         rmbrak(1);
  824.         if (top->type == THEN) {
  825.         rmbrak(1);
  826.         checkelse();
  827.         }
  828.     }
  829.     }
  830. }
  831.